﻿using AppInfo;
using BoardGame;
using GameModel;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using System.IO;
using System.Reflection;
using System.Diagnostics;


namespace ChessWinControllerSpace
{
    public partial class ChessWinController : Form
    {
        // For the full class diagram, make this public.
        // (A friend reference to the diagram tool would be nice here.)
        private ChessModel chessGameModel;

        // Create the Model-View-Controller triad.  Start with the View.
        public ChessWinController ()
        {
            InitializeComponent ();
        }

        #region Checkerboard pseudo-control

        internal readonly int CellSize = 48;
        internal Color LightSquares = Color.SandyBrown;
        internal Color DarkSquares = Color.Chocolate;

        [System.Diagnostics.CodeAnalysis.SuppressMessage ("Microsoft.Performance", "CA1814:PreferJaggedArraysOverMultidimensional", MessageId = "Member")]
        private Icon[,] boardIcons;
        [System.Diagnostics.CodeAnalysis.SuppressMessage ("Microsoft.Performance", "CA1814:PreferJaggedArraysOverMultidimensional", MessageId = "Member")]
        private bool[,] isHilited;

        private bool hasSelection;

        private void CheckerboardCtor (int xSize, int ySize)
        {
            // Create the view's empty matrix.
            boardIcons = new Icon[xSize, ySize];
            isHilited = new bool[xSize, ySize];
        }

        public Coordinate Selection { get; private set; }

        public void ClearSelection ()
        {
            if (hasSelection)
            {
                hasSelection = false;
                SetHilite (Selection.X, Selection.Y, false);
            }
        }

        public void SetSelection (int newX, int newY)
        {
            if (hasSelection && Selection.X != newX && Selection.Y != newY)
                ClearSelection ();

            hasSelection = true;
            Selection = new Coordinate (newX, newY);
            SetHilite (newX, newY, true);
        }

        public void SetHilite (int x, int y, bool newHilite)
        {
            isHilited[x, y] = newHilite;
            InvalidateSquare (x, y);
        }

        public void ClearHilites ()
        {
            ClearSelection ();

            for (int y = 0; y < 8; ++y)
                for (int x = 0; x < 8; ++x)
                    if (isHilited[x, y])
                    {
                        isHilited[x, y] = false;
                        InvalidateSquare (x, y);
                    }
        }

        public void SetIcon (int x, int y, Icon newIcon)
        {
            boardIcons[x, y] = newIcon;
            InvalidateSquare (x, y);
        }

        public void InvalidateSquare (int x, int y)
        {
            int xPoint = x * CellSize;
            int yPoint = ClientRectangle.Height - (y + 1) * CellSize;
            Invalidate (new Rectangle (xPoint, yPoint, CellSize, CellSize));

            string s = String.Format ("Invalidating {0},{1} size={2}", xPoint.ToString (), yPoint.ToString (), CellSize);
            Debug.WriteLine (s);
        }

        #endregion


        private void ChessWinController_Shown (object sender, EventArgs e)
        {
            Assembly assembly = Assembly.GetExecutingAssembly ();
            Text = AppAbout.Product (assembly) + ' ' + AppAbout.Version (assembly);

            chessGameModel = new ChessModel ();

            // Create widgets that are dependent on the Model.
            CheckerboardCtor (chessGameModel.Board.XSize, chessGameModel.Board.YSize);

            // Create the View and connect to the Model.
            ChessWinView winView = new ChessWinView (this, chessGameModel);
        }


        private void ChessWinController_Paint (object sender, PaintEventArgs e)
        {
            int cellSize = CellSize;
            Debug.WriteLine ("Clip::");
            Debug.WriteLine (e.ClipRectangle);

            Rectangle rec = ClientRectangle;

            SolidBrush specialBrush = new SolidBrush (Color.Purple);
            SolidBrush darkBrush = new SolidBrush (DarkSquares);
            SolidBrush lightBrush = new SolidBrush (LightSquares);

            int xMin = e.ClipRectangle.X / cellSize;
            int xMax = (e.ClipRectangle.X + e.ClipRectangle.Width - 1) / cellSize;
            if (xMax >= chessGameModel.Board.XSize - 1)
                xMax = chessGameModel.Board.XSize - 1;

            int yMin = (rec.Height - (e.ClipRectangle.Y + e.ClipRectangle.Height)) / cellSize;
            int yMax = (rec.Height - e.ClipRectangle.Y - 1) / cellSize;
            if (yMax > chessGameModel.Board.YSize - 1)
                yMax = chessGameModel.Board.YSize - 1;
            Debug.WriteLine ("xMin=" + xMin + " xMax=" + xMax + " yMin=" + yMin + " yMax=" + yMax
                + " clientH=" + rec.Height + " clipY=" + e.ClipRectangle.Y);

            for (int y = yMin; y <= yMax; ++y)
                for (int x = xMin; x <= xMax; ++x)
                {
                    Debug.WriteLine ("Drawing cell (" + x + "," + y + ")");
                    int x0 = cellSize * x, y0 = rec.Height - cellSize * (y + 1);

                    SolidBrush squareBrush = (x + y) % 2 == 0 ? darkBrush : lightBrush;
                    SolidBrush brush = isHilited [x, y] ? specialBrush : squareBrush;
                    Rectangle cellRec = new Rectangle (x0, y0, cellSize, cellSize);

                    e.Graphics.FillRectangle (brush, x0, y0, cellSize, cellSize);

                    if (isHilited [x, y])
                    {
                        Pen squarePen = new Pen (squareBrush);
                        e.Graphics.DrawLine (squarePen, x0, y0, x0 + cellSize - 1, y0);
                        e.Graphics.DrawLine (squarePen, x0, y0, x0, y0 + cellSize - 1);
                        e.Graphics.DrawLine (squarePen, x0 + cellSize - 1, y0, x0 + cellSize - 1, y0 + cellSize - 1);
                        e.Graphics.DrawLine (squarePen, x0, y0 + cellSize - 1, x0 + cellSize - 1, y0 + cellSize - 1);
                    }

                    Icon icon = boardIcons[x,y];
                    if (icon != null)
                        e.Graphics.DrawIcon (icon, cellRec);
                }

            specialBrush.Dispose ();
            darkBrush.Dispose ();
            lightBrush.Dispose ();
        }


        Point CellFromClient (int clientX, int clientY)
        {
            return new Point (clientX / CellSize, (ClientRectangle.Height - clientY) / CellSize);
        }


        private void ChessWinController_Click (object sender, EventArgs e)
        {
            if (!chessGameModel.IsUnderway)
                return;

            MouseEventArgs arg = e as MouseEventArgs;

            if (arg != null)
            {
                Debug.WriteLine ("CLICK @" + arg.X.ToString () + "," + arg.Y.ToString ());

                int newX = arg.X / CellSize;
                int newY = (ClientRectangle.Height - arg.Y) / CellSize;

                if (arg.Button == MouseButtons.Left)
                {
                    if (!hasSelection)
                    {
                        if (chessGameModel.IsMovable (newX, newY))
                            SetSelection (newX, newY);
                    }
                    else
                        if (Selection.X == newX && Selection.Y == newY)
                        {
                            Debug.WriteLine ("SAME");
                            ClearSelection ();
                        }
                        else
                        {
                            try
                            {
                                chessGameModel.MakeMove (Selection.X, Selection.Y, newX, newY);
                            }
                            catch (InvalidOperationException ex)
                            {
                                MessageBox.Show (ex.Message, "SORRY");
                            }
                        }
                }
            }
        }

        private void ChessWinController_MouseDown (object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                Point p = CellFromClient (e.X, e.Y);
                chessGameModel.BeginShowMoves (p.X, p.Y);
            }
        }

        private void ChessWinController_MouseUp (object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
                chessGameModel.EndShowMoves ();
        }


        private void ChessWinController_ResizeEnd (object sender, EventArgs e)
        {
            Invalidate ();
        }

        ////////  ////////  ////////  ////////  ////////  ////////  ////////  ////////  


        private void fileMenuExit_Click (object sender, EventArgs e)
        {
            Application.Exit ();
        }


        private void gameMenuNew_Click (object sender, EventArgs e)
        {
            chessGameModel.SetupStandard ();
        }


        private void gameMenuResign_Click (object sender, EventArgs e)
        {
            chessGameModel.ResignGame ();
        }


        private void gameMenuUndo_Click (object sender, EventArgs e)
        {
            try
            {
                chessGameModel.UndoMove ();
            }
            catch (InvalidOperationException ex)
            {
                MessageBox.Show (ex.Message, "UNEXPECTED ERROR");
            }
        }

        ////////

        private void drawMenuRequest_Click (object sender, EventArgs e)
        {
            string playerName = ChessModel.PlayerName (chessGameModel.PlayerTurn);
            string opponentName = ChessModel.PlayerName (ChessModel.Opponent (chessGameModel.PlayerTurn));

            DialogResult answer = MessageBox.Show
            (
                playerName + " has requested a draw. Do you approve?",
                "Message to " + opponentName,
                MessageBoxButtons.YesNo,
                MessageBoxIcon.Question
            );

            if (answer == DialogResult.No)
            {
                MessageBox.Show
                (
                    "Opponent has declined your draw request.",
                    "Message to " + playerName
                );
                return;
            }

            try
            {
                chessGameModel.DrawGame ();
            }
            catch (InvalidOperationException ex)
            {
                MessageBox.Show (ex.Message, "UNEXPECTED ERROR");
            }
        }


        private void drawMenuNoCaptures_Click (object sender, EventArgs e)
        {
            try
            {
                chessGameModel.DrawGame ();
            }
            catch (InvalidOperationException ex)
            {
                MessageBox.Show (ex.Message, "UNEXPECTED ERROR");
            }
        }


        private void drawMenuRepetitive_Click (object sender, EventArgs e)
        {
            try
            {
                chessGameModel.DrawGame ();
            }
            catch (InvalidOperationException ex)
            {
                MessageBox.Show (ex.Message, "UNEXPECTED ERROR");
            }
        }

        ////////

        private void helpMenuAbout_Click (object sender, EventArgs e)
        {
            Form dlg = new WinAbout ();
            dlg.ShowDialog ();
            dlg.Dispose ();
        }

        ////////


        private void promoList_SelectionChangeCommitted (object sender, EventArgs e)
        {
            chessGameModel.SetPromotion (promoList.Text);
        }
    }
}
